package com.ruoyi.web.controller.pinko;

import com.ruoyi.common.annotation.Anonymous;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.common.utils.poi.ExcelUtil;
import com.ruoyi.system.domain.PinkoBlocknetwork;
import com.ruoyi.system.domain.PinkoBlocknetworkLog;
import com.ruoyi.system.service.IPinkoBlocknetworkLogService;
import com.ruoyi.system.service.IPinkoBlocknetworkService;
import io.swagger.annotations.ApiOperation;
import io.swagger.v3.oas.annotations.Operation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicReference;
import java.util.regex.Matcher;
import java.util.regex.Pattern;


/**
 * 区块链网络信息Controller
 * 
 * @author ruoyi
 * @date 2024-06-07
 */
@RestController
@RequestMapping("/system/blocknetwork")
public class PinkoBlocknetworkController extends BaseController
{
    @Autowired
    private IPinkoBlocknetworkService pinkoBlocknetworkService;
    @Autowired
    private IPinkoBlocknetworkLogService pinkoBlocknetworkLogService;
    /**
     * 查询区块链网络信息列表
     */
    @PreAuthorize("@ss.hasPermi('system:blocknetwork:list')")
    @GetMapping("/list")
    public TableDataInfo list(PinkoBlocknetwork pinkoBlocknetwork)
    {
        startPage();
        List<PinkoBlocknetwork> list = pinkoBlocknetworkService.selectPinkoBlocknetworkList(pinkoBlocknetwork);
        return getDataTable(list);
    }

    /**
     * 导出区块链网络信息列表
     */
    @PreAuthorize("@ss.hasPermi('system:blocknetwork:export')")
    @Log(title = "区块链网络信息", businessType = BusinessType.EXPORT)
    @PostMapping("/export")
    public void export(HttpServletResponse response, PinkoBlocknetwork pinkoBlocknetwork)
    {
        List<PinkoBlocknetwork> list = pinkoBlocknetworkService.selectPinkoBlocknetworkList(pinkoBlocknetwork);
        ExcelUtil<PinkoBlocknetwork> util = new ExcelUtil<PinkoBlocknetwork>(PinkoBlocknetwork.class);
        util.exportExcel(response, list, "区块链网络信息数据");
    }

    /**
     * 获取区块链网络信息详细信息
     */
    @PreAuthorize("@ss.hasPermi('system:blocknetwork:query')")
    @GetMapping(value = "/{id}")
    public AjaxResult getInfo(@PathVariable("id") Long id)
    {
        return success(pinkoBlocknetworkService.selectPinkoBlocknetworkById(id));
    }

    /**
     * 新增区块链网络信息
     */
    @PreAuthorize("@ss.hasPermi('system:blocknetwork:add')")
    @Log(title = "区块链网络信息", businessType = BusinessType.INSERT)
    @PostMapping
    public AjaxResult add(@RequestBody PinkoBlocknetwork pinkoBlocknetwork) {
        //先查询当前网络名称 、区块浏览器URL 是否已存在
        PinkoBlocknetwork pinkoBlocknetworkSel = new PinkoBlocknetwork();
        pinkoBlocknetworkSel.setBlockbrowserUrl(pinkoBlocknetwork.getBlockbrowserUrl());
        pinkoBlocknetworkSel.setNetworkName(pinkoBlocknetwork.getNetworkName());
        pinkoBlocknetworkSel.setChainId(pinkoBlocknetwork.getChainId());
        pinkoBlocknetworkSel.setCurrencySymbols(pinkoBlocknetwork.getCurrencySymbols());
        pinkoBlocknetworkSel.setRpcUrl(pinkoBlocknetwork.getRpcUrl());
        List<PinkoBlocknetwork> list = pinkoBlocknetworkService.selectPinkoBlocknetworkList(pinkoBlocknetworkSel);
        if (!list.isEmpty() && list != null) {
            return toAjax(0);
        }
        pinkoBlocknetwork.setUpdateDate(new Date());
        pinkoBlocknetwork.setUpdater(pinkoBlocknetwork.getCreator());
        pinkoBlocknetwork.setUpdaterName(pinkoBlocknetwork.getCreatorName());
        int resultA = pinkoBlocknetworkService.insertPinkoBlocknetwork(pinkoBlocknetwork);
        if (resultA > 0) {
            String actDescription = "";
            String action = "";
            list = pinkoBlocknetworkService.selectPinkoBlocknetworkList(pinkoBlocknetworkSel);
            if (list.size() > 0) {
                PinkoBlocknetwork firstItem = list.get(0);
                action = "CREATE";
                actDescription = "新增币种网络管理";
                SaveActionLog(firstItem, action, actDescription);          }
        }
        return toAjax(resultA);
    }
    public void SaveActionLog(PinkoBlocknetwork dto,String action ,String actDescription)
    {
        PinkoBlocknetworkLog dtolog =new PinkoBlocknetworkLog();
        dtolog.setCreateDate(dto.getUpdateDate());
        dtolog.setCreator(dto.getUpdater());
        dtolog.setCreatorName(dto.getUpdaterName());
        dtolog.setFatherId(dto.getId());
        dtolog.setNetworkName(dto.getNetworkName());//""
        dtolog.setChainId(dto.getChainId());//"链ID"
        dtolog.setAction(action);
        dtolog.setActiondescription(actDescription);
        pinkoBlocknetworkLogService.insertPinkoBlocknetworkLog(dtolog);


    }
    /**
     * 修改区块链网络信息
     */
    @PreAuthorize("@ss.hasPermi('system:blocknetwork:edit')")
    @Log(title = "区块链网络信息", businessType = BusinessType.UPDATE)
    @PutMapping
    public AjaxResult edit(@RequestBody PinkoBlocknetwork pinkoBlocknetwork)
    {
        pinkoBlocknetworkService.updatePinkoBlocknetwork(pinkoBlocknetwork);
        String actDescription="";
        String action="";
        actDescription="更新数据";
        action="UPDATE";
        SaveActionLog(pinkoBlocknetwork,action,actDescription);
        return success();
    }

    /**
     * 删除区块链网络信息
     */
    @PreAuthorize("@ss.hasPermi('system:blocknetwork:remove')")
    @Log(title = "区块链网络信息", businessType = BusinessType.DELETE)
	@DeleteMapping("/{ids}")
    public AjaxResult remove(@PathVariable Long[] ids)
    {
        String actDescription="";
        String action="";
        actDescription="删除数据";
        action="DELETED";
        for (long idstr:ids) {
            PinkoBlocknetwork data = pinkoBlocknetworkService.selectPinkoBlocknetworkById(idstr);
            if(data!=null&&data.getNetworkName().length()>0){
                data.setUpdaterName("");
                SaveActionLog(data,action,actDescription);
            }
        }
        return toAjax(pinkoBlocknetworkService.deletePinkoBlocknetworkByIds(ids));
    }
    @ApiOperation("获取币种网络信息")
    @GetMapping("getList")
    @Anonymous
    @Operation(summary = "查询")
    public AjaxResult getList(){
        List<PinkoBlocknetwork>  entities= pinkoBlocknetworkService.selectPinkoBlocknetworkList(null);
        return success(entities);
    }


    @ApiOperation("获取cpe信息")
    @GetMapping("/cpedemo")
    @Anonymous
    public R<String> CPETest() throws Exception
    {
        String returnStr="这是一个测试";
        /*String acsUrl = "http://192.168.88.132:7547/";
        URL httpUrl = new URL(acsUrl);
        AtomicReference<String> authorization = new AtomicReference<>("initial_token");
        String soapR="";
        //(DBI dbi, Properties properties)

        Tr069Controller tr069Controller=new Tr069Controller();
        // 创建 MockHttpServletRequest
        MockHttpServletRequest request = new MockHttpServletRequest();
        request.setContent("your request body".getBytes());

        // 创建 MockHttpServletResponse
        MockHttpServletResponse response = new MockHttpServletResponse();

        // 创建 Authentication 对象
        Authentication authentication = new UsernamePasswordAuthenticationToken(
                "cpe", "cpe");

        // 调用 doPost 方法
        ResponseEntity<String> result = tr069Controller.doPost(authentication, request, response);

        System.out.println(result.getBody());
        return  R.ok(returnStr);

        //step 1: 判断连接是否在线，不在线重新获取authorization值
        //需要解析acs发过来的关闭连接
        if(callCPEConne(acsUrl,authorization)) {

        }else {
            System.out.println("failed to connect to " + acsUrl);
        }

        //step 2:使用账户代开连接
        // 打开连接并设置请求头
        HttpURLConnection httpConnection = (HttpURLConnection) httpUrl.openConnection();
        setHeaders(httpConnection,soapR,authorization);
        // 建立连接并获取响应码
        int httpCode = httpConnection.getResponseCode();
        System.out.println("httpCode : = " + httpCode);
        httpConnection.disconnect();
        //step 3:发送soap请求
        GetParameterValuesHandlerTest object=new GetParameterValuesHandlerTest();
        object.init();
        soapR = object.xml;
        httpConnection = (HttpURLConnection) httpUrl.openConnection();
        httpConnection.setRequestProperty("Content-type", "text/xml; charset=utf-8");
        httpConnection.setRequestMethod("GET");
        httpConnection.setDoOutput(true);
        if(!"".equals(soapR)) {
            // 写入请求数据
            try (OutputStream outputStream = httpConnection.getOutputStream();
                 OutputStreamWriter writer = new OutputStreamWriter(outputStream)) {
                writer.write(soapR);
                writer.flush();
            }
        }
        // 建立连接并获取响应码
        httpCode = httpConnection.getResponseCode();
        System.out.println("httpCode : = " + httpCode);
        // 关闭连接
        httpConnection.disconnect();
        */
        return R.ok(returnStr);
    }

    /**
     * 设置header认证
     * */
    private static void setHeaders(HttpURLConnection httpConnection,String soapMessage, AtomicReference<String> authorization) throws Exception{
        // 设置请求头
        httpConnection.setRequestProperty("Content-type", "text/xml; charset=utf-8");
        if(!"".equals(soapMessage)) {
            httpConnection.setRequestProperty("SOAPAction", "\"urn:dslforum-org:cwmp-1-0#GetParameterValues\"");
        }
        // 设置基本认证
        String username = "cpe";
        String password = "cpe";
        String realm = "realm@easycwmp";
        String nonce = "";
        String lstr = authorization.get();
        // 定义正则表达式
        Pattern pattern = Pattern.compile("nonce=\"([^\"]+)\"");
        Matcher matcher = pattern.matcher(lstr);

        // 查找匹配
        if (matcher.find()) {
            nonce = matcher.group(1);
        }
        String opaque = "328458fab28345ae87ab3210a8513b14eff452a2";
        String qop = "auth";
        String method = "GET";
        String uri = "/";
        // 计算 Digest 认证头
        String ha1 = calculateHA1(username, realm, password);
        String ha2 = calculateHA2(method, uri, soapMessage);
        String response = calculateResponse(nonce, ha1, ha2, qop, "00000001");


        String authHeader = String.format(
                "Digest username=\"%s\", realm=\"%s\", nonce=\"%s\", uri=\"%s\", qop=%s, nc=00000001, cnonce=\"cnonce\", response=\"%s\", opaque=\"%s\"",
                username, realm, nonce, uri, qop, response, opaque
        );
        httpConnection.setRequestProperty("Authorization", authHeader);

        //httpConnection.setRequestMethod("GET");
        httpConnection.setDoOutput(true);
    }

    private static String calculateHA1(String username, String realm, String password) throws NoSuchAlgorithmException, NoSuchAlgorithmException {
        MessageDigest md = MessageDigest.getInstance("MD5");
        byte[] input = (username + ":" + realm + ":" + password).getBytes(StandardCharsets.UTF_8);
        byte[] digest = md.digest(input);
        return bytesToHex(digest);
    }

    private static String calculateHA2(String method, String uri, String body) throws NoSuchAlgorithmException {
        MessageDigest md = MessageDigest.getInstance("MD5");
        byte[] input = (method + ":" + uri).getBytes(StandardCharsets.UTF_8);
        byte[] digest = md.digest(input);
        return bytesToHex(digest);
    }

    private static String calculateResponse(String nonce, String ha1, String ha2, String qop, String nc) throws NoSuchAlgorithmException {
        MessageDigest md = MessageDigest.getInstance("MD5");
        byte[] input = (ha1 + ":" + nonce + ":" + nc + ":cnonce:" + qop + ":" + ha2).getBytes(StandardCharsets.UTF_8);
        byte[] digest = md.digest(input);
        return bytesToHex(digest);
    }

    private static String bytesToHex(byte[] bytes) {
        StringBuilder hexString = new StringBuilder();
        for (byte b : bytes) {
            String hex = Integer.toHexString(0xff & b);
            if (hex.length() == 1) {
                hexString.append('0');
            }
            hexString.append(hex);
        }
        return hexString.toString();
    }
    /**
     * 测试cpe连接，获得authorization值
     */
    public static boolean callCPEConne(String acsUrl, AtomicReference<String> authorization)  throws Exception{

        boolean connected=false;
        URL httpUrl = new URL(acsUrl);
        HttpURLConnection connection=null;
        try {
            connection=(HttpURLConnection)httpUrl.openConnection();
            connection.setReadTimeout(4000);
            int code=connection.getResponseCode();
            if(code==200 || code==204)
                connected=true;
        } catch (IOException e) {
            connected=false;

        }
        finally {
            // 获取响应头部信息
            Map<String, List<String>> headers = connection.getHeaderFields();
            for (Map.Entry<String, List<String>> entry : headers.entrySet()) {
                System.out.println("Header: " + entry.getKey() + " = " + entry.getValue());
                if("WWW-Authenticate".equals( entry.getKey()))
                {// 修改传入的授权令牌
                    authorization.set( entry.getValue().get(0));
                }
            }
            connection.disconnect();
        }
        return connected;
    }

}
